!!M Inlines.f
c!!S USER


C
C  This is the filter proc for modal dialog which supports the validation
C  of text entry.
C
C  Written by Jeff E Mandel MD MS 1990
C

	logical*1 function NumValFilter ( theDialog , theEvent , itemHit )
	
	implicit none
	
!!SETC USINGINCLUDES = .FALSE.
	Include	'TYPES.F'
	Include	'DIALOGS.F'
	include 'EVENTS.F'
	include 'SANE.F'

	include 'format.inc'
	
	record /decimal/ d
	record /decform/ f
	integer*1 r
	extended x
	string*255 s , s1
	logical*1 validprefix
	integer*2 index , activeItem
	
	Record /DialogRecord/ theDialog
	Record /EventRecord/  theEvent
	pointer /resourcePtrType/ formatHandle
	structure /stringPointer/
		pointer /integer*1/ ptr
	end structure
	integer*1 lenByte
	integer*2 theKeys(0:7)
	
	logical good
	common /numValFilt/ good
	
	pointer /stringPointer/ stringHandle

	record /Rect/ box , defaultBox
	integer*4 itemHandle , PrivateEvent
	integer*2 ItemType
	
	integer*2 ptrue

	integer*4 offset , len1 , j , theNum , ptr1 , sourcePtr
	integer*2 itemHit , i , theField , Drag
	character*1 theChar
	character*256 debugChar
	logical validate
	
	DATA	ptrue / 1 /
	
	if ( theEvent.what .eq. keyDown .or. theEvent.what .eq. autoKey ) then
		theNum = jiand ( theEvent.message , charCodeMask )
		formatHandle = theDialog.window.refCon
C
C  If the dialog has no format resource, handle return and enter but do nothing else
C
		if ( formatHandle .eq. 0 ) then
			if ( theNum .eq. 3 .or. theNum .eq. 13 ) then
				NumValFilter = ptrue
				itemHit = theDialog.aDefItem
			else
				NumValFilter = .false.
			end if
			go to 20
		end if

C
C  Figure out which item in the format resource handles the current item. The
C  current item is recovered from editField
C

		validate = .false.
		theField = theDialog.editField+1
		do i = 1 , formatHandle^.Ptr^.count
			if (formatHandle^.Ptr^.format(i).theItem .eq. theField) then
				activeItem = i
				validate = .true.
				leave
			end if
		end do

		if ( (theNum .eq. 3 .or. theNum .eq. 13) .and. ( good .or.
	1		(theDialog.aDefItem .ne. formatHandle^.Ptr^.okItem) )) then
				NumValFilter = ptrue
				itemHit = theDialog.aDefItem
		else if ( .not. validate ) then
			NumValFilter = .false.
		else if ( theNum .eq. 9 ) then
C
C  This is tricky. If we have the text partieally selected, and the value is bad,
C  and the user hits the tab key, we need to foce a redraw of the invalidation, as
C  otherwise the dialog manager will have redrawn the selected text in the undimmed
C  state, confusing the user.
C
			if ( ((theDialog.textH.TEH^.TEP^.selStart .ne.
	1			   theDialog.textH.TEH^.TEP^.selEnd) .or.
	2			  (theDialog.textH.TEH^.TEP^.nLines .gt. 1 ) ) .and.
	3			   formatHandle^.Ptr^.format(activeItem).badVal ) then
				call GetDItem ( theDialog , %val(theField) , ItemType , itemHandle , box )
				call InvalRect ( box )
			end if
			NumValFilter = .false.
		else if ( theNum .ge. 28 .and. theNum .le. 31 ) then
C
C  ASCII codes we don't handle
C
			NumValFilter = .false.
		else if ( formatHandle^.Ptr^.format(activeItem).theType .eq. TextFormat ) then
C
C  TextFormat - the only criterion for validation is the number of characters. If a valid
C  key is hit, increment the count by one, unless the key is delete. The only trick is if
C  there is a selection, account for the fact that multiple characters will vanish
C

			call GetDItem ( %ref(theDialog) , %val(theField) , ItemType , itemHandle , box )
			call GetIText ( %val(itemHandle) , %ref(s) )
			len1 = theDialog.textH.TEH^.TEP^.selEnd - theDialog.textH.TEH^.TEP^.selStart
			index = len(s)
			if ( theNum .eq. 8 ) then
				if ( len1 .eq. 0 .and. theDialog.textH.TEH^.TEP^.selStart .ne. 0 ) len1 = 1
				index = index - len1
			else
				index = index - len1 + 1
			end if
			x = QFLOAT ( index ) 
			call GetDItem ( %ref(theDialog) , %val(formatHandle^.Ptr^.defaultItem)
	1						, ItemType , itemHandle , defaultBox )
			if ( 	(x .lt. formatHandle^.Ptr^.format(activeItem).minVal) 
	1		   .or. (x .gt. formatHandle^.Ptr^.format(activeItem).maxVal) ) then
					formatHandle^.Ptr^.format(activeItem).badVal = .true.
					call InvalRect ( box )
					call InvalRect ( defaultBox )
					good = .false.
			else if  ( formatHandle^.Ptr^.format(activeItem).badVal ) then
				formatHandle^.Ptr^.format(activeItem).badVal = .false.
				call InvalRect ( box )
				call InvalRect ( defaultBox )
			end if
			NumValFilter = .false.
		else if ( (formatHandle^.Ptr^.format(activeItem).theType .eq. IntegerFormat) .and. theNum .eq. 46 ) then
C
C  Ignore the decimal point in integer fields
C
			NumValFilter = .false.
			theEvent.what = NullEvent
		else if ( theNum .eq. 45 .or. theNum .eq. 46 .or. theNum .eq. 8
	1				 .or. (theNum .ge. 48 .and. theNum .le. 57)) then

C  We have a number which must be incorporated into the string. Since the user
C  could have moved the insertion point, or even dragged over any or all of the
C  item's contents, we use the toolbox Munger (IM-I pp468-9) to properly kludge
C  the string. Note that the delete key must be treated as a special case.

			call GetDItem ( %ref(theDialog) , %val(theField) , ItemType , itemHandle , box )
			call GetIText ( %val(itemHandle) , %ref(s) )
			stringHandle = NewString ( %ref(s) )
			offset = theDialog.textH.TEH^.TEP^.selStart + 1
			len1 = theDialog.textH.TEH^.TEP^.selEnd - theDialog.textH.TEH^.TEP^.selStart
			if ( theNum .eq. 8 
	1		  .and. .not.(theDialog.textH.TEH^.TEP^.selStart .eq. 0 
	2		  .and.	len1 .eq. 0) ) then
				if ( len1 .eq. 0 ) then
					len1 = 1
					offset = offset - 1
				end if
				ptr1 = NewPtr ( %val(len1) )
				sourcePtr = stringHandle^.ptr
				sourcePtr = sourcePtr + offset
				call BlockMove ( %val(sourcePtr) , %val(ptr1) , %val(len1) )
				j = Munger ( %val(stringHandle) , %val(offset) , %val(ptr1) ,
	1				 %val(len1) , %ref(0) , %val(0) )
				call DisposPtr ( %val(ptr1) )
			else
				theChar =  char (theNum)
				j = Munger ( %val(stringHandle) , %val(offset) , %val(0)
	1					 , %val(len1) ,	%ref(theChar) , %val(1) )
			end if
			lenByte = GetHandleSize ( %val(stringHandle) ) - 1
			stringHandle^.ptr^ = lenByte
			index = 1
C
C  Convert the string to a DECFORM to see if it is valid. If not, reject the keystroke
C

			call STR2DEC ( %val(stringHandle^.ptr) , index , d , validprefix)
			call DisposHandle ( %val(stringHandle) )
			if ( .not. validprefix ) then
				NumValFilter = .false.
				theEvent.what = NullEvent
			else
C
C  We have a number! See if it is in the valid range
C

				x = DEC2NUM(d)
				call GetDItem ( %ref(theDialog) , %val(formatHandle^.Ptr^.defaultItem)
	1							, ItemType , itemHandle , defaultBox )
				if ( 	(x .lt. formatHandle^.Ptr^.format(activeItem).minVal) .or.
	1					(x .gt. formatHandle^.Ptr^.format(activeItem).maxVal) ) then
C
C  It is not. Set the badVal flag for the field, and invalRect the cooperating
C  userItems that handle graying.
C
					formatHandle^.Ptr^.format(activeItem).badVal = .true.
					call InvalRect ( box )
					call InvalRect ( defaultBox )
					good = .false.
				else if  ( formatHandle^.Ptr^.format(activeItem).badVal ) then
C
C  The inverse
C
					formatHandle^.Ptr^.format(activeItem).badVal = .false.
					call InvalRect ( box )
					call InvalRect ( defaultBox )
				end if

				NumValFilter = .false.
			end if
		else
			NumValFilter = .false.
			theEvent.what = NullEvent
		end if

	else if ( theEvent.what .eq. mouseDown ) then
		formatHandle = theDialog.window.refCon
		if ( formatHandle .ne. 0  .and. itemHit .gt. 0 ) then
			theField = theDialog.editField+1
			do i = 1 , formatHandle^.Ptr^.count
C
C  Similar to the tabbing problem described above, except we have to search to find
C  the correct item
C
				if (formatHandle^.Ptr^.format(i).theItem .eq. theField) then
					if ( ((theDialog.textH.TEH^.TEP^.selStart .ne. 
	1					   theDialog.textH.TEH^.TEP^.selEnd) .or.
	2						(theDialog.textH.TEH^.TEP^.nLines .gt. 1 ) ) .and.
	3						formatHandle^.Ptr^.format(activeItem).badVal ) then
						call GetDItem ( theDialog , %val(theField) , ItemType , itemHandle , box )
						call InvalRect ( box )
					end if
					leave
				end if
			end do
		end if
		NumValFilter = .false.
	else if ( theEvent.what .eq. NullEvent ) then
		formatHandle = theDialog.window.refCon
		if ( formatHandle .eq. 0 ) then
			NumValFilter = .false.
			go to 20
		end if
C
C  Handle the pressing of the option key, which displays the vaidation criteria in
C  the cooperating staticText item
C
		call GetKeys ( theKeys )
		if ( bitest( theKeys(3) , 2 ) .and. origField ) then
			theField = theDialog.editField+1
			do i = 1 , formatHandle^.Ptr^.count
				if (formatHandle^.Ptr^.format(i).theItem .eq. theField) then
					call GetDItem ( theDialog , %val(formatHandle^.Ptr^.format(i).theLabel)
	1								, ItemType , origFieldHandle , box )
					call GetIText ( %val(origFieldHandle) , %ref(origFieldText) )
					if ( formatHandle^.Ptr^.format(i).theType .eq. IntegerFormat ) then
						r = TOWARDZERO
						f.style = FIXEDDECIMAL
						f.digits = 0
						call SETROUND(r)
						x = formatHandle^.Ptr^.format(i).minVal
						call NUM2STR(f,x,%ref(s))
						x = formatHandle^.Ptr^.format(i).maxVal
						call NUM2STR(f,x,%ref(s1))
						s = s // ' ² value ² ' // s1
					else if ( formatHandle^.Ptr^.format(i).theType .eq. RealFormat ) then
						r = TONEAREST
						f.style = FIXEDDECIMAL
						f.digits = 1
						call SETROUND(r)
						x = formatHandle^.Ptr^.format(i).minVal
						call NUM2STR(f,x,%ref(s))
						x = formatHandle^.Ptr^.format(i).maxVal
						call NUM2STR(f,x,%ref(s1))
						s = s // ' ² value ² ' // s1
					else if ( formatHandle^.Ptr^.format(i).theType .eq. TextFormat ) then
						r = TOWARDZERO
						f.style = FIXEDDECIMAL
						f.digits = 0
						call SETROUND(r)
						x = formatHandle^.Ptr^.format(i).minVal
						call NUM2STR(f,x,%ref(s))
						x = formatHandle^.Ptr^.format(i).maxVal
						call NUM2STR(f,x,%ref(s1))
						s = s // ' ² # chars ² ' // s1
					end if
					call SetIText ( %val(origFieldHandle) , %ref(s) )
					origField = .false.
					leave
				end if
			end do
		else if ( .not. bitest( theKeys(3) , 2 ) .and. .not. origField ) then
C
C  Restore on option key up
C
			call SetIText ( %val(origFieldHandle) , %ref(origFieldText) )
			origField = .true.
		end if
		NumValFilter = .false.
	else
		NumValFilter = .false.
	end if
20	return
	
	end
